home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume90 / util / uujoin / part01 / UUJoin.c < prev    next >
C/C++ Source or Header  |  1990-10-10  |  8KB  |  331 lines

  1. /*
  2.  * uujoin [ -r ] [ {-amiga | -mac | -pc} ] file(s)...
  3.  * join and decode Usenet encoded binary files.
  4.  *
  5.  * Author:  Mark R. Rinfret
  6.  * Date:    08-15-90
  7.  * 
  8.  * Public Domain - Use as you wish.
  9.  *
  10.  * Notes:   The uudecode portion was adapted from uudecode.c, packaged
  11.  *          with Matt Dillon's UUCP implementation.
  12.  *
  13.  *          The Macintosh mode simply filters and joins the files. It
  14.  *          doesn't decode the BinHex format (got a de-binhexer I can
  15.  *          have?).
  16.  *
  17.  *          The delimiter strings used to extract the encoded segments
  18.  *          may change over time. Just edit the assignments to the
  19.  *          string variables "start" and "stop", as appropriate.
  20.  */
  21.  
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <FileScan.h>
  26.  
  27. extern int unlink(const char *fileName);
  28.  
  29. extern int errno;
  30.  
  31. /* single character decode */
  32. #define DEC(c)    (((c) - ' ') & 077)
  33.  
  34. int decode(FILE *in, FILE *out);
  35. int outdec(char *p, FILE *f, int n);
  36. int fr(FILE *fd, char *buf, int cnt);
  37.  
  38. #define AMI     0
  39. #define MAC     1
  40. #define PC      2
  41.  
  42. int     fileCount;                          /* set by FileScan() */
  43. char    **fileNames;                        /* allocated by FileScan() */
  44. int     fileNumber;                         /* index into fileNames */
  45. char    line[256];                          /* allows for long Usenet lines */
  46. int     machine;                            /* machine type */
  47. int     removeFiles = 0;                    /* 1 => remove originals */
  48. char    tempName[L_tmpnam];                 /* temporary file name */
  49.  
  50. int
  51. DecodeMergedFile(void)
  52. {
  53.     char    dest[128];
  54.  
  55.     FILE    *in = NULL, *out = NULL;
  56.     int     mode;                               /* file protection */
  57.  
  58.     in = fopen(tempName, "r");
  59.     if (! in ) {
  60.         fprintf(stderr,"Could not reopen merged file: '%s'\n", tempName);
  61.         exit(1);
  62.     }
  63.  
  64.     /* Search for header line */
  65.     for (;;) {
  66.         if (fgets(line, sizeof line, in) == NULL) {
  67.             fprintf(stderr, "No begin line\n");
  68.             exit(1);
  69.         }
  70.         if (strncmp(line, "begin ", 6) == 0)
  71.             break;
  72.     }
  73.  
  74.     sscanf(line, "begin %o %s", &mode, dest);
  75.  
  76.     /* create output file */
  77.     out = fopen(dest, "w");
  78.     if (out == NULL) {
  79.         perror(dest);
  80.         exit(1);
  81.     }
  82.  
  83.     decode(in, out);
  84.  
  85.     if (fgets(line, sizeof line, in) == NULL || strcmp(line, "end\n")) {
  86.         fprintf(stderr, "No end line\n");
  87.         exit(5);
  88.     }
  89.     fclose(in);
  90.  
  91.     return 0;
  92. }
  93.  
  94. int
  95. JoinFiles(void)
  96. {
  97.     char    *fName;                         /* current file name */
  98.     FILE    *inFile = NULL;
  99.     char    *p;                             /* adjusted line pointer */
  100.     char    *start, *stop;                  /* pattern matching strings */
  101.     int     startLeng, stopLeng;            /* pattern lengths */
  102.     int     status = 0;
  103.     FILE    *tempFile = NULL;
  104.  
  105.     tmpnam(tempName);
  106.     tempFile = fopen(tempName, "w");
  107.     if (!tempFile) {
  108.         perror(tempName);
  109.         status = errno;
  110.         goto done;
  111.     }
  112.  
  113.     /* Set up pattern strings according to machine type. Patterns are
  114.      * matched from beginning of line through number of chars in pattern. 
  115.      */
  116.  
  117.     if (machine == MAC) {
  118.         start = "---";
  119.         stop = "--- end";
  120.     }        
  121.     else if (machine == PC) {
  122.         start = "BEGIN";
  123.         stop = "END--";
  124.     }
  125.     else {                              /* AMIGA */
  126.         start = "sed";
  127.         stop = "SHAR_EOF";
  128.     }
  129.     
  130.     /* Compute the lengths of the match strings. */
  131.  
  132.     startLeng = strlen(start);
  133.     stopLeng = strlen(stop);
  134.  
  135.     /* The Amiga binaries are packaged as shar files and therefore have a
  136.      * leading 'X' which must be tossed. Other formats (so far) are not
  137.      * packed as shar files and thus, the whole line is used.
  138.      */
  139.     p = (machine == AMI ? (line + 1) : line);
  140.  
  141.     while (fileNumber < fileCount) {
  142.         fName = fileNames[fileNumber];  /* For programming convenience. */
  143.         inFile = fopen(fName, "r");
  144.         if (! inFile) {
  145.             perror(fName);
  146.             status = errno;
  147.             goto done;
  148.         }
  149.  
  150.         /*  Attempt to find the start of this file. */
  151.  
  152.         if (startLeng) {
  153.             while (1) {
  154.                 fgets(line, sizeof(line), inFile);
  155.                 if ( feof(inFile) ) {
  156. eof_err:
  157.                     fprintf(stderr,"uujoin: unexpected EOF in file '%s'!\n", fName);
  158.                     status = EOF;
  159.                     goto done;
  160.                 }
  161.                 if (strncmp(start, line, startLeng) == 0)
  162.                     break;                      /* We found the beginning. */
  163.             }
  164.         }
  165.  
  166.         while (1) {
  167.             fgets(line, sizeof(line), inFile);
  168.             if ( feof(inFile) ) {
  169.                 if (stopLeng == 0) 
  170.                     break;
  171.                 else
  172.                     goto eof_err;
  173.             }
  174.  
  175.             if ( (*line != '\n') && (strncmp(stop, line, stopLeng) == 0) )
  176.                 break;                      /* We found the end. */
  177.         
  178.             if ( fputs(p, tempFile) ) {     /* Write the _adjusted_ line. */
  179.                 status = EOF;
  180.                 fprintf(stderr,"uujoin: error writing to temp file '%s'\n", 
  181.                         tempName);
  182.                 exit(1);
  183.             }
  184.         }
  185.         fclose(inFile);
  186.         ++fileNumber;
  187.     }
  188.  
  189. done:
  190.     if (tempFile) fclose(tempFile);
  191.     if (inFile) fclose(inFile);
  192.     return status;
  193. }
  194.  
  195. main(int argc, char **argv)
  196. {
  197.  
  198.     if (argc < 2) {
  199. usage:
  200.         puts("Program: uujoin - join and decode Usenet encoded binary files.");
  201.         puts("Usage:   uujoin [options] file1 [... filen]");
  202.         puts("Where [options] may be:");
  203.         puts("\t-amiga  -> uuencoded files wrapped with shar");
  204.         puts("\t-mac    -> Macintosh binhex files (not decoded in this release)");
  205.         puts("\t-pc     -> uuencoded files enclosed in BEGIN/END pairs");
  206.         puts("\t-r      -> remove original files when done");
  207.         puts("\n\tUnix-style wildcards may be used in file specifications.");
  208.         puts("\n\tExample: uujoin -amiga -r program.??");
  209.         puts("\n\tMark R. Rinfret, August 1990.");
  210.         puts("\tContributed to the public domain.");
  211.         exit(1);
  212.     }
  213.     
  214.     --argc;                                 /* Skip over program name. */
  215.     ++argv;
  216.  
  217.     while (**argv == '-') {
  218.         if (strcmp(*argv,"-mac") == 0) {
  219.             machine = MAC;
  220. bump:
  221.             --argc;                         /* Skip this arg. */
  222.             ++argv;
  223.         }
  224.         else if (strcmp(*argv, "-pc") == 0) {
  225.             machine = PC;
  226.             goto bump;
  227.         }
  228.         else if (strcmp(*argv,"-amiga") == 0) {
  229.             machine = AMI;
  230.             goto bump;
  231.         }
  232.         else if (strcmp(*argv,"-r") == 0) {
  233.             removeFiles = 1;
  234.             goto bump;
  235.         }
  236.         else
  237.             goto usage;
  238.     }
  239.  
  240.     fileNames = FileScan(argv, argc, &fileCount, 1);
  241.     if (! fileNames) {
  242.         printf("Filename expansion failed - abort!\n");
  243.         exit(1);
  244.     }
  245.  
  246.     if (JoinFiles()) exit(1);                   /* Attempt to join files. */
  247.  
  248.     if (DecodeMergedFile()) exit(1);
  249.  
  250.     unlink(tempName);
  251.     if (removeFiles) {
  252.         while (--fileCount >= 0) {
  253.             unlink(fileNames[fileCount]);
  254.         }
  255.     }
  256.     exit(0);
  257. }
  258.  
  259. /*
  260.  * copy from in to out, decoding as you go along.
  261.  */
  262. decode(in, out)
  263. FILE *in;
  264. FILE *out;
  265. {
  266.     char buf[80];
  267.     char *bp;
  268.     int n;
  269.  
  270.     for (;;) {
  271.         /* for each input line */
  272.         if (fgets(buf, sizeof buf, in) == NULL) {
  273.             printf("Short file\n");
  274.             exit(10);
  275.         }
  276.         n = DEC(buf[0]);
  277.         if (n <= 0)
  278.             break;
  279.  
  280.         bp = &buf[1];
  281.         while (n > 0) {
  282.             outdec(bp, out, n);
  283.             bp += 4;
  284.             n -= 3;
  285.         }
  286.     }
  287. }
  288.  
  289. /*
  290.  * output a group of 3 bytes (4 input characters).
  291.  * the input chars are pointed to by p, they are to
  292.  * be output to file f.  n is used to tell us not to
  293.  * output all of them at the end of the file.
  294.  */
  295. outdec(p, f, n)
  296. char *p;
  297. FILE *f;
  298. {
  299.     int c1, c2, c3;
  300.  
  301.     c1 = DEC(*p) << 2 | DEC(p[1]) >> 4;
  302.     c2 = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
  303.     c3 = DEC(p[2]) << 6 | DEC(p[3]);
  304.     if (n >= 1)
  305.         fputc(c1, f);
  306.     if (n >= 2)
  307.         fputc(c2, f);
  308.     if (n >= 3)
  309.         fputc(c3, f);
  310. }
  311.  
  312.  
  313. /* fr: like read but stdio */
  314. int
  315. fr(fd, buf, cnt)
  316. FILE *fd;
  317. char *buf;
  318. int cnt;
  319. {
  320.     int c, i;
  321.  
  322.     for (i=0; i<cnt; i++) {
  323.         c = fgetc(fd);
  324.         if (c == EOF)
  325.             return(i);
  326.         buf[i] = c;
  327.     }
  328.     return (cnt);
  329. }
  330.  
  331.